
#include "Self_Define_Functions.h"

using namespace std;




bool Compare_NewType( NewType data1, NewType data2 )
{
    return data1.data > data2.data;
}

bool Compare_NewType2( NewType data1, NewType data2 )
{
    return data1.data < data2.data;
}

void Ranking_basedfitness_increase( int *ranking, NewType *tempsortfitness, double *input, int num)
{
    int i,j;

    for( i = 0; i < num; ++i )
    {
        tempsortfitness[i].data = input[i];
        tempsortfitness[i].id = i;
    }

    sort( tempsortfitness, tempsortfitness+num, Compare_NewType2 );

    for( i = 0; i < num; ++i )
    {
        ranking[tempsortfitness[i].id] = i;
    }
    //return ranking;
}
void Ranking_basedfitness_decrease( int *ranking, NewType *tempsortfitness, double *input, int num)
{
    int i,j;

    for( i = 0; i < num; ++i )
    {
        tempsortfitness[i].data = input[i];
        tempsortfitness[i].id = i;
    }

    sort( tempsortfitness, tempsortfitness+num, Compare_NewType );

    for( i = 0; i < num; ++i )
    {
        ranking[tempsortfitness[i].id] = i;
    }
    
}
void Ranking_baseddistance_increase( int **ranking_dis, NewType **tempsortdistance, double **input, int num)
{
    int i,j;

    for( i = 0; i < num; ++i )
    {
        for( j = 0; j < num; ++j )
        {
            tempsortdistance[i][j].data = input[i][j];
            tempsortdistance[i][j].id = j;
        }
    }
    for( i = 0; i < num; ++i )
    {
        
            sort( tempsortdistance[i], tempsortdistance[i]+num, Compare_NewType2 );
        
    }   

    for( i = 0; i < num; ++i )
    {
        for( j = 0; j < num; ++j )
        {
            
            ranking_dis[i][tempsortdistance[i][j].id] = j;
            
        }
        
    }
    
}

double Fitness ( double *particle, int &Fes, CEC2013 *pFunc )
{
    Fes++;
    return pFunc->evaluate( particle );
}


void Popupation_Fitness( double **population, int population_size, int &Fes, double *result, CEC2013 *pFunc )
{
    int i;
    for ( i = 0; i < population_size; ++i )
    {
        result[i] = pFunc->evaluate( population[i] );

    }

    Fes += population_size;
}


void Select_Rand_Number(int base, int range, int *selected_numbers, int num, double **q,double *results)
{
	int i, j;

	boost::mt19937 generator(time(0)*rand());
	boost::uniform_int<> uniform_int_particle(0, range - 1);
	boost::variate_generator< boost::mt19937&, boost::uniform_int<> > random_int_particle(generator, uniform_int_particle);

    boost::uniform_real<> uniform_real_generate_r( 0, 1 );
    boost::variate_generator< boost::mt19937&, boost::uniform_real<> > random_real_num_r( generator, uniform_real_generate_r );

	int *temp = new int[num + 1];
	bool found = true;

	double p_Roulette;

	temp[0] = base;

	for (i = 0; i < num; ++i)
	{
		found = true;
		while (found)
		{
			found = false;

			//Making a choice with cumulative fitness			
			p_Roulette = random_real_num_r();

			for ( j = 0; j < range; ++j)
			{
				if (p_Roulette <= q[base][j])
				{
                    selected_numbers[i] = j;
                    break;
                }
			}
			
			for (j = 0; j < i+1; ++j)
			{
                
				if (selected_numbers[i] == temp[j])
				{
					found = true;
					break;
				}
			}			
		}
		temp[i + 1] = selected_numbers[i];
	}
    //Pick the best of the three, the next best, and the last
    /*for(i=0;i<num-1;++i)
	{
		for(j=i+1;j<num;++j)
		{
			if(results[selected_numbers[j]]>results[selected_numbers[i]])//按降序排列
			{
                swap( selected_numbers[i], selected_numbers[j] );
            }
        }		
	}*/
  
    //Choose the best of the three
    double three_max=results[selected_numbers[0]];
    int max_index = 0;

    for(i=1;i<num;++i)
	{
			
        if(results[selected_numbers[i]]>three_max)//只找最大
		{
            three_max=results[selected_numbers[i]];
            max_index = i;
        }
    }

    if( max_index != 0 )
    {
        swap( selected_numbers[0], selected_numbers[max_index] );
    }
        
	delete[]temp;	
}

//DE-rand-1// // please note that first, the child is the copy of its parent, and then it will be send to this function
void DE_Child( double *child, double *parent1, double *parent2, double *parent3, int dim, double*LBound, double *UBound, double cr, double F )
{
    int i;

    boost::mt19937 generator(time(0)*rand());
    boost::uniform_real<> uniform_real_generate_r( 0, 1 );
    boost::variate_generator< boost::mt19937&, boost::uniform_real<> > random_real_num_r( generator, uniform_real_generate_r );


    boost::uniform_int<> uniform_int_dim( 0, dim-1 );
    boost::variate_generator< boost::mt19937&, boost::uniform_int<> > random_int_dim( generator, uniform_int_dim );

    int dim_rand = random_int_dim();


    for( i = 0; i < dim; ++i )
    {
        if( random_real_num_r() < cr || i == dim_rand )
        {
            double unmuted = 0;
            unmuted = child[i];     // For special boundary update mode learned from the literature

            child[i] = parent1[i] + F*( parent2[i] - parent3[i] );
            if( child[i] < LBound[i] )
            {
                child[i] = (double)((double)(unmuted + LBound[i])/(double)2);
            }

            if( child[i] > UBound[i] )
            {
                child[i] = (double)((double)(unmuted + UBound[i])/(double)2);
            }
        }

    }

}

//DE-currenttorand-1//// please note that first, the child is the copy of its parent, and then it will be send to this function
void DE_Child1( double *parenti,double *child, double *parent1, double *parent2, double *parent3, int dim, double*LBound, double *UBound, double cr, double F )
{
    int i;

    boost::mt19937 generator(time(0)*rand());
    boost::uniform_real<> uniform_real_generate_r( 0, 1 );
    boost::variate_generator< boost::mt19937&, boost::uniform_real<> > random_real_num_r( generator, uniform_real_generate_r );


    boost::uniform_int<> uniform_int_dim( 0, dim-1 );
    boost::variate_generator< boost::mt19937&, boost::uniform_int<> > random_int_dim( generator, uniform_int_dim );

    int dim_rand = random_int_dim();


    for( i = 0; i < dim; ++i )
    {
        if( random_real_num_r() <= cr || i == dim_rand )
        {
            double unmuted=0;
            unmuted=child[i];

            child[i] = parenti[i] + F*( parent1[i] - parenti[i] )+ F*( parent2[i] - parent3[i] );
            if( child[i] < LBound[i] )
            {
                child[i] = (double)((double)(unmuted + LBound[i])/(double)2);
            }

            if( child[i] > UBound[i] )
            {
                child[i] = (double)((double)(unmuted + UBound[i])/(double)2);
            }
        }

    }

}

double Distance( double *vector1, double *vector2, int dim )
{
    double sum = 0;
    for( int i = 0; i < dim; ++i )
    {
        sum += pow( vector1[i] - vector2[i], 2);
    }

    return sqrt( sum );
}

double Distance( double *vector1, vector<double> vector2, int dim )
{
    assert( vector2.size() == dim );

    double sum = 0;
    for( int i = 0; i < dim; ++i )
    {
        sum += pow( vector1[i] - vector2[i], 2);
    }

    return sqrt( sum );
}



int Close_Particle( double *child, double **population, int population_size, int dim )
{
    double min_distance = 1e100;

    int i;

    int particle_index = -1;

    double temp_distance;

    for( i = 0; i < population_size; ++i )
    {
        temp_distance = Distance( child, population[i], dim );
        if( min_distance > temp_distance )
        {
            min_distance = temp_distance;
            particle_index = i;
        }
    }


    return particle_index;

}

void Get_Seeds( double **population, double *population_results, int population_size, int dim, vector<double> &seed_fitness, double radius )
{
    int i,j;
    bool found;
    double dist;

    vector< vector<double> > seeds;


    //sort population
    NewType *temp = new NewType [population_size];
    for( i = 0; i < population_size; ++i )
    {
        temp[i].data = population_results[i];
        temp[i].id = i;
    }


    sort( temp, temp+population_size, Compare_NewType );

    seed_fitness.clear();

    for( i = 0; i < population_size; ++i )
    {
        found = false;

        for( j = 0; j < seeds.size(); ++j )
        {
            dist = Distance( population[temp[i].id], seeds[j], dim );
            if( dist <= radius )
            {
                found = true;
                break;
            }
        }

        if( !found )
        {
            vector<double> temp_seed( population[temp[i].id], population[temp[i].id] + dim );
            seeds.push_back(temp_seed);
            seed_fitness.push_back( population_results[temp[i].id] );
        }

    }


    delete []temp;
    seeds.clear();
}





int How_Many_Global_Optima( vector<double> seed_fitness, double epsilon, CEC2013 *pFunc )
{

    int  counter = 0;;
	for ( unsigned int  i = 0; i < seed_fitness.size(); ++i )
	{
		/* |F_seed - F_goptimum| <= accuracy */
		if ( fabs(seed_fitness[i] - pFunc->get_fitness_goptima()) <= epsilon)
		{
			++counter;
		}
		/* save time */
		if (counter == pFunc->get_no_goptima())
            break;
	}
	return counter;

}


int Compute_Global_Optima_Found( double **population, double *population_results, int population_size, int dim, double epsilon, CEC2013 *pFunc )
{
    vector<double> seed_fitness;

    Get_Seeds( population, population_results,  population_size, dim, seed_fitness, pFunc->get_rho() );

    int counter = How_Many_Global_Optima( seed_fitness,  epsilon, pFunc );

    seed_fitness.clear();

    return counter;

}

void adaptiveFcr( int population_size, int *ranking, NewType *tempsortfitness, double *results, double *cr, double *F ,double *tempresults,double *Fcr)
{
    int i,j;

    for( i = 0; i < population_size; ++i )
    {
        tempresults[i] = results[i];
    }
    sort(tempresults,tempresults+population_size,less<double>());

    for( i = 0; i < population_size; ++i )
    {
        Fcr[i]=(double)((double)(tempresults[population_size-1]-results[i]+yigexino)/(double)(tempresults[population_size-1]-tempresults[0]+yigexino));            
    }

    for( i = 0; i < population_size; ++i )
    {
        boost::mt19937 generator2(time(0) * rand());
        boost::normal_distribution<> nor(Fcr[i], 0.1);
        boost::variate_generator< boost::mt19937&, boost::normal_distribution<> > normal(generator2, nor);
        
      	do
       	{
           	F[i] = normal(); 
        }while( F[i] <= 0 );
        if( F[i] > 1 )
	    {
		    F[i] = 1; 
	    }
	    cr[i] = normal(); 
	    if( cr[i] > 1 )
	    {
		    cr[i] = 1; 
	    }
	    if( cr[i] < 0 )
	    {
		    cr[i] = 0; 
	    }
    }

}
void adaptiveFcr1( int base,int selected_particle_indexbase, int population_size, int *ranking, NewType *tempsortfitness, double *results, double *cr, double *F ,double *tempresults,double *Fcr,double *Fcr1)
{
  

    Fcr[base]=(double)((double)(tempresults[population_size-1]-results[selected_particle_indexbase]+yigexino)/(double)(tempresults[population_size-1]-tempresults[0]+yigexino));            
    
    Fcr1[base]=(double)((double)(tempresults[population_size-1]-results[base]+yigexino)/(double)(tempresults[population_size-1]-tempresults[0]+yigexino));            
   
    
    boost::mt19937 generator2(time(0) * rand());
    boost::normal_distribution<> nor(Fcr[base], 0.1);
    boost::variate_generator< boost::mt19937&, boost::normal_distribution<> > normal(generator2, nor);
        
        
      	do
       	{
            F[base] = normal(); 
        }while( F[base] <= 0 );
        if( F[base] > 1 )
	    {
		    F[base] = 1; 
	    }
 	//boost::mt19937 generator2(time(0) * rand());
    boost::normal_distribution<> nor1(Fcr1[base], 0.1);
    boost::variate_generator< boost::mt19937&, boost::normal_distribution<> > normal1(generator2, nor1);
	
    cr[base] = normal1(); 
	if( cr[base] > 1 )
	{
		cr[base] = 1; 
	}
	if( cr[base] < 0 )
	{
		cr[base] = 0; 
	}
    

}
// Adaptive local search
void PLS( int population_size, int dim,int &Fes,int MAX_FES,int *ranking,NewType *tempsortfitness,double *tempresults1,double *results, double *PLSsigma, double PLSxbetter_fitness,double *PLSP,double *PLSxbetter,double *PLSxnew_fitness,double **PLSxnew,double **population,double*LBound, double *UBound,CEC2013 *pFunc )
{
    int i,j,k;
    for( i = 0; i < population_size; ++i )
    {
        PLSsigma[i]=(double)(4);
        
        PLSsigma[i]=(double)((double)(PLSsigma[i]*Fes)/MAX_FES);
        
        PLSsigma[i]=(double)(-1-PLSsigma[i]);
        
        PLSsigma[i]=pow(10,PLSsigma[i]);       
    }
     
    for( i = 0; i < population_size; ++i )
    {
        tempresults1[i] = results[i];
    }
    sort(tempresults1,tempresults1+population_size,less<double>());

    for( i = 0; i < population_size; ++i )
    {
        PLSP[i]=(double)((double)(results[i]-tempresults1[0]+yigexino)/(double)(tempresults1[population_size-1]-tempresults1[0]+yigexino));
    
    }

    boost::mt19937 generator(time(0)*rand());
    boost::uniform_real<> uniform_real_generate_r( 0, 1 );
    boost::variate_generator< boost::mt19937&, boost::uniform_real<> > random_real_num_r( generator, uniform_real_generate_r );
    
    //boost::mt19937 generator2(time(0) * rand());
    for( i = 0; i < population_size; ++i )
    {
        
        if(random_real_num_r()<=PLSP[i])
        {

            for( k = 0; k < 1; ++k )
            {
                for( j = 0; j < dim; ++j )
                {
                    boost::mt19937 generator2(time(0) * rand());
                    boost::normal_distribution<> nor(population[i][j], PLSsigma[i]);
                    boost::variate_generator< boost::mt19937&, boost::normal_distribution<> > normal(generator2, nor); 

                    PLSxnew[k][j]=normal();
                    if( PLSxnew[k][j] < LBound[j] )     //Out of bounds treatment
                    { 
                        PLSxnew[k][j] =(double)((double)(population[i][j] + LBound[j])/(double)2);
                    }

                    if( PLSxnew[k][j] > UBound[j] )
                    {
                        PLSxnew[k][j] =(double)((double)(population[i][j] + UBound[j])/(double)2);
                    }
                }
                PLSxnew_fitness[k] = Fitness( PLSxnew[k], Fes, pFunc );
                
                if( PLSxnew_fitness[k] > results[i] )
                {
                    results[i] = PLSxnew_fitness[k];
                    memcpy( population[i], PLSxnew[k], sizeof(double)*dim );
                }
            }
          
        }
    }

}

//using sort
void Ranking_Distance_sort( double sigma,int population_size, int dim,NewType **tempsortdistance,int **rank_result, double **temp_distance, double **W,double **P,double **q,double **population)
{
    int i,j,k;
    // Calculated distance
    for (i = 0; i < population_size; ++i)
	{
		for (j = i; j < population_size; ++j)
		{       
			temp_distance[i][j] = temp_distance[j][i]=Distance(population[i], population[j], dim);
                        
		}
	}
    // Distance sort
	Ranking_baseddistance_increase( rank_result, tempsortdistance, temp_distance, population_size);
	// Calculate the selection probability according to the weight function
	for (i = 0; i < population_size; ++i)
	{
        W[i][i]=0;
		for (j = 0; j < population_size; ++j)
		{
            
            if(j!=i)
            {
                W[i][j] = (double)(-(rank_result[i][j] - 1)*(rank_result[i][j] - 1) / (double)(2 * sigma*sigma*population_size*population_size));

                W[i][j] = exp(W[i][j]); 
                            
                W[i][j] = (double)(1 / (double)(sigma*population_size*sqrt(2 * PI)))*W[i][j];

            }
            
		}

        double Wsum = 0;
		for ( k = 0; k < population_size; ++k)
		{
			Wsum += W[i][k];
		}
		for (j = 0; j < population_size; ++j)
		{

			P[i][j] = W[i][j] / Wsum;

		}

	}

	for (i = 0; i < population_size; ++i)
	{
        q[i][0]=P[i][0];
		for (j = 1; j < population_size; ++j)
		{           
            q[i][j] = q[i][j-1]+P[i][j];						
		}
	}
}